import { Timeline, Animation, ease } from './animation/animation';
import { VComponent } from './framework';
import { enableGesture } from './gesture/gesture';

export class Carousel extends VComponent {
  protected root: HTMLDivElement | null = null;

  private ax: number = 0;
  private timer: number = -1;

  private time: number = 0;
  private timeline: Timeline = new Timeline();
  

  render() {
    this.root = document.createElement('div');
    this.root.classList.add('v-carousel');

    for (let record of this.attributes['src']) {
      const child = document.createElement('div');

      child.style.backgroundImage = `url('${record.img}')`;

      this.root.appendChild(child);
    }

    // 监听 root 上面的手势事件
    enableGesture(this.root);

    this.root.addEventListener('pan', this.handlePan);
    this.root.addEventListener('end', this.handleEnd);

    this.timeline.start();
    this.time = 0;

    this.state.position = 0;
    
    this.root.addEventListener('start', () => {
      this.timeline.pause();
      window.clearInterval(this.timer);

      if (Date.now() - this.time < 500) {
        const progress = (Date.now() - this.time) / 500;
        this.ax = ease(progress) * 500 - 500;
      } else {
        this.ax = 0;
      }
    });

    this.root.addEventListener('tap', () => {
      this.triggerEvent('click', {
        data: this.attributes.src[this.state.position],
        position: this.state.position,
      });
    });

    this.timer = window.setInterval(this.nextPicture, 3000);

    return this.root;
  }

  nextPicture = () => { 
    if (this.root == null) {
      window.clearInterval(this.timer);
      return;
    }

    const children = this.root.children;
    let nextImageIndex = (this.state.position + 1) % children.length;

    const currentImage = children[this.state.position] as HTMLImageElement;
    const nextImage = children[nextImageIndex] as HTMLImageElement;

    this.time = Date.now();

    this.timeline.add(
      new Animation(
        currentImage.style,
        'transform',
        -this.state.position * 500,
        -500 - this.state.position * 500,
        500,
        0,
        ease,
        v => `translateX(${v}px)`,
      ),
    );

    this.timeline.add(
      new Animation(
        nextImage.style,
        'transform',
        500 - nextImageIndex * 500,
        -nextImageIndex * 500,
        500,
        0,
        ease,
        v => `translateX(${v}px)`,
      ),
    );

    this.triggerEvent('change', {
      position: this.state.position,
    });
    this.state.position = nextImageIndex;
  }

  handlePan = (event: Event & Record<string, any>) => {
    const children = this.root?.children;

    if (children == null) {
      return;
    }

    const x = event.clientX - event.startX - this.ax;

    const currentImageIndex = this.state.position - (x - x % 500) / 500;

    for (let offset of [-1, 0, 1]) {
      let index = currentImageIndex + offset;
      index = (index % children.length + children.length) % children.length;
      const child = children[index] as HTMLImageElement;

      child.style.transition = 'none';
      child.style.transform = `translateX(${-index * 500 + offset * 500 + x % 500}px)`;
    }
  }

  handleEnd = (event: Event & Record<string, any>) => {
    const children = this.root?.children;

    if (children == null) {
      return;
    }

    this.timeline.reset();
    this.timeline.start();
    this.timer = window.setInterval(this.nextPicture, 3000);

    const x = event.clientX - event.startX - this.ax;
    let current = this.state.position - (x - x % 500) / 500;
    let direction = Math.round((x % 500) / 500);

    if (event.isFlick) {
      if (event.velocity < 0) {
        direction = Math.ceil((x % 500) / 500);
      } else {
        direction = Math.floor((x % 500) / 500);
      }
    }

    // FIXME: 这里其实还是会有问题的，应该计算全部图片的位置
    for (let offset of [-1, 0, 1]) {
      let index = current + offset;
      index = (index % children.length + children.length) % children.length;

      const child = children[index] as HTMLImageElement;

      this.timeline.add(
        new Animation(
          child.style,
          'transform',
          -index * 500 + offset * 500 + x % 500,
          -index * 500 + offset * 500 + direction * 500,
          500,
          0,
          ease,
          v => `translateX(${v}px)`,
        ),
      );
    }

    this.state.position = this.state.position - ((x - x % 500) / 500) - direction;
    this.state.position = (this.state.position % children.length + children.length) % children.length;

    this.triggerEvent('change', {
      position: this.state.position,
    });
  }
}